package com.ecahack.busstop.activities;

import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.json.JSONException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.ecahack.busstop.R;
import com.ecahack.busstop.data.Bus;
import com.ecahack.busstop.data.BusStop;
import com.ecahack.busstop.json.BusListGrabber;
import com.ecahack.busstop.json.JSONParser;
import com.ecahack.busstop.utils.BusListViewAdapter;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class StopActivity extends BaseBusStopActivity {

	private static final String TAG = "StopActivity";
	private static final double DEFAUT_LOC = -117;

	private static final int DEFAULT_ZOOM = 17;

	private Menu mMenu;
	private BusListViewAdapter mBusListAdapter;
	private ListView mBusList;
	private TextView mDescriptionTv;
	private ProgressBar mLoading;
	private Button mNumberHeader;
	private Button mTimeHeader;
	private TextView mClock;

	private double mCurrLat;
	private double mCurrLong;

	private LatLng mCurrentLocation;

	private boolean mNumberAscceding;

	private String mSelectedBusStopLocId;
	private LoadBuListTask mBusListLoader;

	private GoogleMap mMap;
	private List<BusStop> mBusStops;

	@SuppressWarnings("unchecked")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_stop);
		Bundle extras = getIntent().getExtras();
		mSelectedBusStopLocId = extras.getString(MainActivity.BUS_STOP_ID);
		mBusStops = (List<BusStop>) extras
				.getSerializable(MainActivity.BUS_STOPS);
		mCurrLat = extras.getDouble(MainActivity.CURRENT_LOCATION_LAT,
				DEFAUT_LOC);
		mCurrLong = extras.getDouble(MainActivity.CURRENT_LOCATION_LONG,
				DEFAUT_LOC);
		if (mCurrLat != DEFAUT_LOC && mCurrLong != DEFAUT_LOC)
			mCurrentLocation = new LatLng(mCurrLat, mCurrLong);

		initialiseViews();
		setListeners();
		if (savedInstanceState == null) {
			startLoadBuListTask();
		} else {
			NonConfigInstance instance = (NonConfigInstance) getLastCustomNonConfigurationInstance();
			if (instance != null) {
				Log.v(TAG, "Retrieved LastCustomNonConfigurationInstance");
				if (instance.mBuses != null) {
					mBusListAdapter.setList(instance.mBuses);
				}
				if (instance.mBusLoader == null) {
					startLoadBuListTask();
				} else {
					// i.e. asynctask is in progress don't do anything
					instance.mBusLoader.setStopActivity(this); // <- reset
																// activity
																// reference to
																// new (this)
					Log.v(TAG, "Loading task is already in progress");
				}
			} else {
				Log.v(TAG, "Unable to get LastCustomNonConfigurationInstance");
			}
		}
	}

	@Override
	protected void onRestart() {
		super.onRestart();
		startLoadBuListTask();
	}

	@Override
	protected void onResume() {
		super.onResume();
		mMap = getMap();
		if (mMap != null) {
			setupMap();
		} else {
			Log.w(TAG, "Unable to get google map");
		}
	}

	private void setupMap() {
		if (mBusStops != null) {
			for (BusStop bs : mBusStops) {
				MarkerOptions marker = new MarkerOptions().position(
						getLatLng(bs)).title(bs.getAddress());
				if (bs.getLocationId().equals(mSelectedBusStopLocId)) {
					marker.icon(BitmapDescriptorFactory
							.fromResource(R.drawable.ic_stop)).title(bs.getDescription());
					mMap.addMarker(marker);
					mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
							getLatLng(bs), DEFAULT_ZOOM));
				} else {
					marker.icon(BitmapDescriptorFactory
							.fromResource(R.drawable.ic_selected_stop)).title(bs.getDescription());
					mMap.addMarker(marker);
				}
			}
			mMap.addMarker(new MarkerOptions()
			.position(mCurrentLocation)
			.icon(BitmapDescriptorFactory
					.fromResource(R.drawable.ic_my_location))
			.title("Me"));
		} else {
			Log.w(TAG, "Bus stop list is null");
		}
	}

	private LatLng getLatLng(BusStop bs) {
		return new LatLng(bs.getLatitude(), bs.getLongitude());
	}

	private GoogleMap getMap() {
		FragmentManager fm = getSupportFragmentManager();
		SupportMapFragment f = (SupportMapFragment) fm
				.findFragmentById(R.id.map_fragment);
		return f.getMap();
	}

	private void initialiseViews() {
		mBusListAdapter = new BusListViewAdapter(this);
		mBusList = (ListView) findViewById(R.id.lvBuses);
		mDescriptionTv = (TextView) findViewById(R.id.tvDetDescription);
		mDescriptionTv.setText(getBusStopByLocId(mSelectedBusStopLocId)
				.getDescription());
		mLoading = (ProgressBar) findViewById(R.id.pbStopLoading);
		mLoading.getIndeterminateDrawable().setColorFilter(0xFF0099cc,
				android.graphics.PorterDuff.Mode.MULTIPLY);
		mNumberHeader = (Button) findViewById(R.id.btnNumberHeader);
		mTimeHeader = (Button) findViewById(R.id.btnTimeHeader);
		mClock = (TextView) findViewById(R.id.tvClock);
		mBusList.setAdapter(mBusListAdapter);
	}

	private void setListeners() {

		mNumberHeader.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				mBusListAdapter.sortByNumber(mNumberAscceding);
				mNumberAscceding = !mNumberAscceding;
			}
		});

		mTimeHeader.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				mBusListAdapter.sortByTime();
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		mMenu = menu;
		getSupportMenuInflater().inflate(R.menu.stop_menu, mMenu);
		return super.onCreateOptionsMenu(mMenu);
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch (item.getItemId()) {
		case R.id.refresh_stop:
			startLoadBuListTask();
			break;

		default:
			break;
		}
		return super.onMenuItemSelected(featureId, item);
	}

	private BusStop getBusStopByLocId(String id) {
		if (mBusStops != null) {
			for (BusStop bs : mBusStops) {
				if (bs.getLocationId().equals(id)) {
					return bs;
				}
			}
		}
		return null;
	}

	private void startLoadBuListTask() {
		if (mBusListLoader == null) {
			BusStop bs = getBusStopByLocId(mSelectedBusStopLocId);
			mBusListLoader = new LoadBuListTask(bs.getLocationId());
			mBusListLoader.setStopActivity(this);
			mBusListLoader.execute();
		}
	}

	@Override
	public Object onRetainCustomNonConfigurationInstance() {
		NonConfigInstance instance = new NonConfigInstance();
		instance.mBuses = mBusListAdapter.getList();
		instance.mBusLoader = mBusListLoader;
		return instance;
	}

	private void setLoading(boolean show) {
		if (show) {
			mLoading.setVisibility(View.VISIBLE);
		} else {
			mLoading.setVisibility(View.GONE);
		}
	}

	private static class LoadBuListTask extends
			AsyncTask<Void, Void, List<Bus>> {

		private static final String TAG = "LoadBusListTask";

		private boolean mJsonError;
		private boolean mIOError;
		private StopActivity mStopActivity;
		private String mLocationId;

		public LoadBuListTask(String locationId) {
			mLocationId = locationId;
		}

		private synchronized void setStopActivity(StopActivity stopActivity) {
			mStopActivity = stopActivity;
		}

		@Override
		protected void onPreExecute() {
			mStopActivity.setLoading(true);
		}

		@Override
		protected List<Bus> doInBackground(Void... params) {
			JSONParser parser = JSONParser.getInstance();
			BusListGrabber busListGrabber = BusListGrabber.getInstance(parser);
			try {
				return busListGrabber.grabBusList(mLocationId);
			} catch (JSONException e) {
				Log.e(TAG, "Unable to get bus list", e);
				mJsonError = true;
			} catch (IOException e) {
				Log.w(TAG, "Caught IOException while getting bus list", e);
				mIOError = true;
			}
			return null;
		}

		@Override
		protected void onPostExecute(List<Bus> buses) {
			if (mIOError) {
				mStopActivity.mDescriptionTv.setText(mStopActivity
						.getString(R.string.service_error_message));
			} else if (mJsonError) {
				mStopActivity.mDescriptionTv.setText(mStopActivity
						.getString(R.string.service_error_message));
			} else {
				if (buses != null) {
					mStopActivity.mBusListAdapter.setList(buses);
					mStopActivity.mClock.setVisibility(View.GONE);
					Log.i(TAG, "Fetched bus stops succesfully");
				} else {
					mStopActivity.mClock.setText(DateFormat.format("h:mm", new Date()));
					mStopActivity.mClock.setVisibility(View.VISIBLE);
					Log.v(TAG, "Bus list is not available");
				}
				mStopActivity.mDescriptionTv.setText(mStopActivity.getBusStopByLocId(mLocationId).getDescription());
			}
			mStopActivity.mBusListLoader = null;
			// TODO: handle the case without internet
			mStopActivity.setLoading(false);
		}
	}

	static class NonConfigInstance {
		List<Bus> mBuses;
		LoadBuListTask mBusLoader;
	}
}
